#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <ncurses.h>
#include <menu.h>

//#include "win_stdscr.h"

#include "win_menu.h"

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD 	4

#if 1
typedef struct 
{
	char key[20];
	char menu[10];

}struct_win_menu;
#endif



const struct_win_menu type_F1_menu[]=
{ 
	{ "SMFI",        "0x1000",	},
	{ "INTC",        "0x1100",	},
	{ "E2CI",        "0x1200",	},
	{ "KBC",         "0x1300",	},
	{ "SWUC",        "0x1400",	},
	{ "PMC",         "0x1500",	},
	{ "GPIO",        "0x1600",	},
	{ "PS/2",        "0x1700",	},
	{ "PWM",         "0x1800",	},
	{ "ADC",         "0x1900",	},
	{ "DAC",         "0x1A00",	},
	{ "WUC",         "0x1B00",	},
	{ "SMBus",       "0x1C00",	},
	{ "KB Scan",     "0x1D00",	},
	{ "ECPM",        "0x1E00",	},
	{ "ETWD",        "0x1F00",	},
	{ "",             "",	},
	//{ (char *)NULL,   (char *)NULL,	},
};

const struct_win_menu type_F2_menu[]=
{ 
	{ "GCTRL",        "0x2000",	},
	{ "EGPC",         "0x2100",	},
	{ "BattRAM",      "0x2200",	},
	{ "CIR",          "0x2300",	},
	{ "TMKBC",        "0x2400",	},
	{ "DBGR",         "0x2500",	},
	{ "SSPI",         "0x2600",	},
	{ "UART0",        "0x2700",	},
	{ "UART1",        "0x2800",	},
	{ "TMR",          "0x2900",	},
	{ "HWM(SIO)",     "0x2A00",	},
	{ "GPIO(SIO)",    "0x2B00",	},
	{ "E-Flash",      "0x2C00",	},
	{ "CEC",          "0x2D00",	},
	{ "USBSW",        "0x2E00",	},
	{ "PECI",         "0x2F00",	},
	{ "ESPI0",        "0x3000",	},
	{ "ESPI1",        "0x3100",	},
	{ "ESPI2",        "0x3200",	},
	{ "ESPI3",        "0x3300",	},
	{ "SMB1",         "0x3400",	},
	{ "SMB2",         "0x3500",	},
	{ "USBPD0",       "0x3600",	},
	{ "USBPD1",       "0x3700",	},
	{ "ESPI0",        "0x3800",	},
	{ "LED DOTMTX",   "0x3900",	},
	{ "LED STRIP",    "0x3A00",	},
	{ "",             "",	},
	//{ (char *)NULL,   (char *)NULL,	},



};

const struct_win_menu type_F3_menu[]=
{ 
	{ "uC SFR",       "0x8000",	},
	{ "uC RAM",       "0xE000",	},

	{ "SRAM0",        "0x0000",	},
	{ "SRAM1",        "0x0100",	},
	{ "SRAM2",        "0x0200",	},
	{ "SRAM3",        "0x0300",	},
	{ "SRAM4",        "0x0400",	},
	{ "SRAM5",        "0x0500",	},
	{ "SRAM6",        "0x0600",	},
	{ "SRAM7",        "0x0700",	},
	{ "SRAM8",        "0x0800",	},
	{ "SRAM9",        "0x0900",	},
	{ "SRAMA",        "0x0A00",	},
	{ "SRAMB",        "0x0B00",	},
	{ "SRAMC",        "0x0C00",	},
	{ "SRAMD",        "0x0D00",	},
	{ "SRAME",        "0x0E00",	},
	{ "SRAMF",        "0x0F00",	},
	//note every struct for menu must add this line .
	// if not add, will be segment core fault
	{ "",             "",	},   
	//{ (char *)NULL,   (char *)NULL,	},

};


const struct_win_menu type_F4_menu[]=
{ 
	{ "SRAM:0x8000",       "(C000)",	},
	{ "SRAM:0x8100",       "(C100)",	},
	{ "SRAM:0x8200",       "(C200)",	},
	{ "SRAM:0x8300",       "(C300)",	},
	{ "SRAM:0x8400",       "(C400)",	},
	{ "SRAM:0x8500",       "(C500)",	},
	{ "SRAM:0x8600",       "(C600)",	},
	{ "SRAM:0x8700",       "(C700)",	},
	{ "SRAM:0x8800",       "(C800)",	},
	{ "SRAM:0x8900",       "(C900)",	},
	{ "SRAM:0x8A00",       "(CA00)",	},
	{ "SRAM:0x8B00",       "(CB00)",	},
	{ "SRAM:0x8C00",       "(CC00)",	},
	{ "SRAM:0x8D00",       "(CD00)",	},
	{ "SRAM:0x8E00",       "(CE00)",	},
	{ "SRAM:0x8F00",       "(CF00)",	},
	{ "SRAM:0x9000",       "(D000)",	},
	{ "SRAM:0x9100",       "(D100)",	},
	{ "SRAM:0x9200",       "(D200)",	},
	{ "SRAM:0x9300",       "(D300)",	},
	{ "SRAM:0x9400",       "(D400)",	},
	{ "SRAM:0x9500",       "(D500)",	},
	{ "SRAM:0x9600",       "(D600)",	},
	{ "SRAM:0x9700",       "(D700)",	},
	{ "SRAM:0x9800",       "(D800)",	},
	{ "SRAM:0x9900",       "(D900)",	},
	{ "SRAM:0x9A00",       "(DA00)",	},
	{ "SRAM:0x9B00",       "(DB00)",	},
	{ "SRAM:0x9C00",       "(DC00)",	},
	{ "SRAM:0X9D00",       "(DD00)",	},
	{ "SRAM:0x9E00",       "(DE00)",	},
	{ "SRAM:0x9F00",       "(DF00)",	},
	

	{ "",             "",	},
	//{ (char *)NULL,   (char *)NULL,	},

};


const struct_win_menu type_F5_menu[]=
{ 
	{ "UART1",       "0x01",	},
	{ "UART2",       "0x02",	},

	{ "SWUC",        "0x04",	},
	{ "KBC_MS",        "0x05",	},
	{ "KBC_KB",        "0x06",	},
	{ "CIR",        "0x0A",	},
	{ "SMFI",        "0x0F",	},
	{ "BRAM",        "0x10",	},
	{ "PMC1",        "0x11",	},
	{ "PMC2",        "0x12",	},
	{ "SPI",        "0x13",	},
	{ "PECI",        "0x14",	},
	{ "PMC3",        "0x17",	},
	{ "PMC4",        "0x18",	},
	{ "PMC5",        "0x19",	},
	{ "",             "",	},
	//{ (char *)NULL,   (char *)NULL,	},

};


const struct_win_menu type_F6_menu[]=
{
#if 01
	{ "EXGPIO",       "",	},
	{ "SwitchEC",       "",	},

	{ "Show Spec Reg",        "",	},
	{ "Save All Reg",        "",	},
	{ "Save Current Page",        "",	},
	{ "Save Byte(Max 32)",        "",	},
	{ "Save Page To Page",        "",	},
	{ "",             "",	},
	//{ (char *)NULL,   (char *)NULL,	},
#endif
#if 0
	{ "EXGPIO",       "",	},
	{ "SwitchEC",       "",	},

	{ "Show Spec Reg",        "",	},
	{ "Save All Reg",        "",	},
	{ "Save Current ",        "",	},
	{ "Save Byte(Max)",        "",	},
	{ "Save Page To ",        "",	},
#endif	
#if 0
	{ "EXGPIO",       "",	},
	{ "SwitchEC",       "",	},

	{ "Show Sp",        "",	},
	{ "Save Al",        "",	},
	{ "Save Cu",        "",	},
	{ "Save By",        "",	},
	{ "Save Pa ",        "",	},
#endif

	
};

typedef struct 
{
	int keyf;
	int num;
	struct_win_menu* pwin_menu;

}struct_win_num_menu;

const struct_win_num_menu type_win_num_menu[]=
{
	{defKeyFMenuBgn+0, sizeof(type_F1_menu)/sizeof(struct_win_menu), (struct_win_menu*)&type_F1_menu},
	{defKeyFMenuBgn+1, sizeof(type_F2_menu)/sizeof(struct_win_menu), (struct_win_menu*)&type_F2_menu},
	{defKeyFMenuBgn+2, sizeof(type_F3_menu)/sizeof(struct_win_menu), (struct_win_menu*)&type_F3_menu},
	{defKeyFMenuBgn+3, sizeof(type_F4_menu)/sizeof(struct_win_menu), (struct_win_menu*)&type_F4_menu},
	{defKeyFMenuBgn+4, sizeof(type_F5_menu)/sizeof(struct_win_menu), (struct_win_menu*)&type_F5_menu},
	{defKeyFMenuBgn+5, sizeof(type_F6_menu)/sizeof(struct_win_menu), (struct_win_menu*)&type_F6_menu},

};



static void print_menu_title(WINDOW *win, int starty, int startx, int width, const char *string, chtype color);

static WINDOW* create_menu_box(int menu_num, const char* strtitle);
WINDOW* create_menu_box(int menu_num, const char* strtitle)
{
	WINDOW *my_menu_win;

    #if 0
    ┌──────────────────────────────────────┐
    │               My Menu                │
    ├──────────────────────────────────────┤
    │ * SMFI    0x1000                     │s
    │   INTC    0x1100                     │
    │   E2CI    0x1200                     │
    │   KBC     0x1300                     │
    │   SWUC    0x1400                     │
    │   PMC     0x1500                     │
    │   GPIO    0x1600                     │
    │   PS/2    0x1700                     │
    │   PWM     0x1800                     │
    │   ADC     0x1900                     │
    │   DAC     0x1A00                     │
    │   WUC     0x1B00                     │
    └──────────────────────────────────────┘
    #endif
	/* Create the window to be associated with the menu */
	#define defWinMenuItmCount 12
	// box top line, title line, the line between title and menu item, box bottom line = 4 lines
	// as the figure
	#define defWinMenuBoxLines 4

	#define defWinMenuHight (defWinMenuItmCount+defWinMenuBoxLines)
	#define defWinMenuWidth 40
	#define defMenuWinLineBgn 2    // y
	#define defMenuWinColBgn 7     // x

    my_menu_win = newwin(defWinMenuHight, defWinMenuWidth, defMenuWinLineBgn, defMenuWinColBgn+5*(menu_num-defKeyFMenuBgn) );
    keypad(my_menu_win, TRUE);
     

	/* Print a border around the main window and print a title */
    box(my_menu_win, 0, 0);

	mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
	mvwhline(my_menu_win, 2, 1, ACS_HLINE, defWinMenuWidth-2);
	mvwaddch(my_menu_win, 2, defWinMenuWidth-1, ACS_RTEE);
    
	print_menu_title(my_menu_win, 1, 0, defWinMenuWidth, strtitle, COLOR_PAIR(1));

	return my_menu_win;
}

MENU* create_menu_for_box(int menu_num, ITEM*** my_items, WINDOW* my_menu_win, int* n_choices)
{
#if 1
	{
		int number;
		for(number=0;number<sizeof(type_win_num_menu)/sizeof(struct_win_num_menu);number++)
		{
			if(menu_num==type_win_num_menu[number].keyf)
			{
				*n_choices = type_win_num_menu[number].num;

				struct_win_menu* pwin_menu=type_win_num_menu[number].pwin_menu;
#if 1
		        (*my_items) = (ITEM **)calloc(*n_choices, sizeof(ITEM *));

		        for(int i = 0; i < (*n_choices); ++i)
		        {
					(*my_items)[i] = new_item((char*)pwin_menu->key, (char*)pwin_menu->menu);
		            pwin_menu++;

		        }
#endif
				break;

			}
		}

	}
#endif

	/* Crate menu */
	MENU *my_menu=my_menu = new_menu( (ITEM **)(*my_items));
	/* Set main window and sub window */
    set_menu_win(my_menu, my_menu_win);
    set_menu_sub(my_menu, derwin(my_menu_win, defWinMenuItmCount, defWinMenuWidth-2, 3, 1));
	set_menu_format(my_menu, defWinMenuItmCount, 1);
			
	/* Set menu mark to the string " * " */
    set_menu_mark(my_menu, " * ");
    	/* Post the menu */
	post_menu(my_menu);
	return my_menu;
}

int response_key_menu_box(int menu_num, WINDOW* my_menu_win, MENU *my_menu, int *pAddr)
{
	int ret;
	//while((c = wgetch(my_menu_win)) != 27 ) // ESC=27
	bool blrunning=true;
	while(blrunning==true)
	{

		int c = wgetch(my_menu_win);

		if(c >= defKeyFMenuBgn  && c <= defKeyFMenuEnd )
		{
			ret=c;
			blrunning=false;		
			continue;
		}


		mvprintw(LINES - 3, 0, 	"c = %d ", c );
		
		refresh();

       switch(c)
        {	case KEY_DOWN:
			menu_driver(my_menu, REQ_DOWN_ITEM);
			break;
		case KEY_UP:
			menu_driver(my_menu, REQ_UP_ITEM);
			break;
		case KEY_NPAGE:
			menu_driver(my_menu, REQ_SCR_DPAGE);
			break;
		case KEY_PPAGE:
			menu_driver(my_menu, REQ_SCR_UPAGE);
			break;

		case 10:	/* Enter */
		//case KEY_ENTER:
			{
				ITEM *cur_item;
				char strdescp[32];
				char strname[32];
				cur_item = current_item(my_menu);
				//ret=item_index(cur_item);
				strncpy(strdescp,item_description(cur_item),sizeof(strdescp));
				strncpy(strname,item_name(cur_item),sizeof(strname));

				blrunning=false;
				move(LINES - 2, 0);
				clrtoeol();
				mvprintw(LINES - 2, 0, 
					"You have chosen %d item with name %s and description %s", 
					menu_num,  strname, 	strdescp);

				//strupr(str);
				if(menu_num!=defKeyFMenuBgn+3)
				{

					char strtmp[32];
					strcpy(strtmp,"0x");
					int nlentmp=strlen(strtmp);
					if(strncmp(strdescp,strtmp,nlentmp)==0)
					{
						char *endptr;
						*pAddr = strtol(&strdescp[nlentmp], &endptr, 16);
						//mvprintw(LINES - 7, 0, "item with strdescp %s *pAddr 0x%08X", &strdescp[nlentmp], *pAddr);
						memset(strtmp,' ',sizeof(strtmp));
						strtmp[sizeof(strtmp)-1]=0x00;
						mvprintw(defnLineBgn + const_nMaxLine +3, defnColBgn, " %s ", strtmp);						
						mvprintw(defnLineBgn + const_nMaxLine +3, defnColBgn, "read type and addr %s %s ", strname, strdescp);
					}

				}
				else
				{
					char strtmp[32];
					strcpy(strtmp,"SRAM:0x");
					int nlentmp=strlen(strtmp);
					if(strncmp(strname,strtmp,nlentmp)==0)
					{
						char *endptr;
						*pAddr = strtol(&strname[nlentmp], &endptr, 16);
						//mvprintw(LINES - 7, 0, "item with name %s *pAddr 0x%08X", &strname[nlentmp], *pAddr);
						memset(strtmp,' ',sizeof(strtmp));
						strtmp[sizeof(strtmp)-1]=0x00;
						mvprintw(defnLineBgn + const_nMaxLine +3, defnColBgn, " %s ", strtmp);
						mvprintw(defnLineBgn + const_nMaxLine +3, defnColBgn, "read type and addr %s %s ", strname, strdescp);
					}					
				}
				//strcasecmp

				#if 0
				mvprintw(LINES - 3, 0, 
					"You have chosen %d item with name %s  description %s *pAddr 0x%08X", 
					menu_num,  strname, strdescp,	*pAddr);
				#endif

				

				refresh();
				pos_menu_cursor(my_menu);


			}

			break;

		}
        wrefresh(my_menu_win);
	}	

	return ret;


}

int win_menu(int menu_num, const char* strtitle, int *pAddr)
{	ITEM** my_items;

	//int c;
	int ret=0;

    int n_choices;

    WINDOW* my_menu_win=create_menu_box(menu_num, strtitle);

	MENU *my_menu=create_menu_for_box( menu_num, &my_items,  my_menu_win, &n_choices);


	//attroff(COLOR_PAIR(2));
	refresh();

	ret=response_key_menu_box( menu_num,  my_menu_win, my_menu, pAddr);

	/* Unpost and free all the memory taken up */
        
    unpost_menu(my_menu);

    free_menu(my_menu);
    for(int i = 0; i < n_choices; ++i)
        free_item(my_items[i]);
	
	if(my_menu_win)
	{
		wborder(my_menu_win, ' ', ' ', ' ',' ',' ',' ',' ',' ');
		wrefresh(my_menu_win);
		delwin(my_menu_win);
	}
	//endwin();
	return ret;

}



void print_menu_title(WINDOW *win, int starty, int startx, int width, const char *string, chtype color)
{	int length, x, y;
	float temp;

	if(win == NULL)
		win = stdscr;
	getyx(win, y, x);
	if(startx != 0)
		x = startx;
	if(starty != 0)
		y = starty;
	if(width == 0)
		width = 80;

	length = strlen(string);
	temp = (width - length)/ 2;
	x = startx + (int)temp;
	//wattron(win, color);
	mvwprintw(win, y, x, "%s", string);
	//wattroff(win, color);
	refresh();
}


